'use strict'
var util = require('../util/index')
var querystring = require('querystring');
var uuid = require('node-uuid')
var https = require('https')
var unzipResponse = require('unzip-response');
class OAuthClient {
  constructor(config) {
    if (!config) throw error('config is required')
    this.key = config.getKey()
    this.secret = config.getSecret()
    this.oauthAddress = config.getOauthAddress()
    this.log = config.getLog()
    var auth = `${this.key}:${this.secret}`;
    this.postOptions = {
      method: 'POST',
      host: this.oauthAddress,
      path: '/token',
      auth: auth,
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Accept-Encoding': 'gzip',
        'User-Agent': 'eleme-openapi-nodejs-sdk'
      },
    }
  }

  // 个人应用获取token
  getToken() {
    var postData = querystring.stringify({
      grant_type: 'client_credentials'
    })
    return this.post(this.postOptions, postData)
  }

  /**
    * 获取授权url
    * @params callbackurl
    * @params state
    * @params scope
    */
  getOAuthUrl(callbackUrl, state, scope) {
    if (!callbackUrl) throw error('callbackUrl is required')
    if (!state) {
      throw new Error('state can not be empty');
    }
    scope = scope || 'all'
    return 'https://' + this.oauthAddress + `/authorize?response_type=code&scope=${scope}`
            + '&client_id=' + this.key
            + '&redirect_uri=' + callbackUrl
            + '&state='
            + state
  }

  /**
    * 根据auth_code获取token
    * @params code
    * @params callbackUrl
    */
  getTokenByCode(code, callbackUrl) {
    if (!code) throw error('code is required')
    if (!callbackUrl) throw error('callbackUrl is required')
    let postData = querystring.stringify({
      grant_type: 'authorization_code',
      code: code,
      redirect_uri: callbackUrl,
      client_id: this.key
    })
    return this.request(this.postOptions, postData);
  }

  /**
    * 根据auth_code获取openId
    * @params code
    * @params callbackUrl
    */
   getOpenIdByCode(code, redirect_uri) {
    if (!code) throw error('code is required')
    if (!redirect_uri) throw error('redirect_uri is required')
    let postData = querystring.stringify({
      grant_type: 'authorization_code',
      code: code,
      redirect_uri: redirect_uri,
      client_id: this.key
    })
    const newLocal = '/identity';
    this.postOptions.path = newLocal
    return this.requestOpenId(this.postOptions, postData)
  }

  /**
    * 根据 refresh_token 更新token
    * @params refreshToken
    * @params scope
    */
  getTokenByRefreshToken(refreshToken, scope) {
    if (!refreshToken) throw error('refreshToken is required')
    scope = scope || 'all'
    var postData = querystring.stringify({
      grant_type: 'refresh_token',
      refresh_token: refreshToken,
      scope: scope
    })
    return this.request(this.postOptions, postData)
  }

  post(options, postData) {
    if (this.log) {
      this.log.info(postData)
    }
    return new Promise(function(resolve, reject) {
      var req = https.request(options, function(res) {
        res = unzipResponse(res)
        res.setEncoding('utf8');
        var json = ''
        res.on('data', function (chunk) {
          json += chunk;
        });
        res.on('end', function() {
          if (this.log) {
            this.log.info(json)
          }
          resolve(json)
        })
      })
      req.on('error', function (e) {
        if (this.log) {
          this.log.error(e)
        }
        reject(e)
      })
      req.write(postData);
      req.end();
    })
  }

  request(options, postData) {
    return new Promise((resolve, reject) => {
     this.post(options, postData)
        .then(res => {
          res = JSON.parse(res)
          if(res.access_token) {
            resolve(res)
          } else {
            reject(res)
          }
        })
    })
  }

  requestOpenId(options, postData) {
    return new Promise((resolve, reject) => {
     this.post(options, postData)
        .then(res => {
          res = JSON.parse(res)
          if(res.openId) {
            resolve(res)
          } else {
            reject(res)
          }
        })
    })
  }
}


module.exports = OAuthClient